from rest_framework import serializers
from django_redis import get_redis_connection
from django.db import transaction
from django.utils import timezone
from decimal import Decimal
import logging

from goods.models import SKU
from .models import OrderInfo, OrderGoods

logger = logging.getLogger('django')


class CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')
    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')


class OrderSettlementSerializer(serializers.Serializer):
    """
    订单结算数据序列化器
    """
    freight = serializers.DecimalField(label='运费', max_digits=10, decimal_places=2)
    skus = CartSKUSerializer(many=True)


class SaveOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderInfo
        fields = ('order_id', 'pay_method', 'address')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'pay_method': {
                'write_only': True,
                'required': True
            },
            'address': {
                'write_only': True,
                'required': True
            }
        }

    def create(self, validated_data):
        address = validated_data['address']
        pay_method = validated_data['pay_method']
        user = self.context['request'].user
        redis_conn = get_redis_connection('cart')
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
        count_dict = {}
        for sku_id in cart_selected:
            count_dict[int(sku_id)] = int(redis_cart[sku_id])
        if not count_dict:
            raise serializers.ValidationError('没有商品需要结算')
        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNSEND'] if pay_method==OrderInfo.PAY_METHODS_ENUM['CASH'] else OrderInfo.ORDER_STATUS_ENUM['UNPAID']
                )
                sku_id_list = count_dict.keys()
                # sku_obj_list = SKU.objects.filter(id__in=sku_id_list)
                for sku_id in sku_id_list:
                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        if origin_stock < count_dict[sku.id]:
                            transaction.savepoint_rollback(save_id)
                            raise serializers.ValidationError('商品%s库存不足' % sku.name)
                        new_stock = origin_stock - count_dict[sku.id]
                        new_sales = origin_sales + count_dict[sku.id]
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if not result:
                            continue
                        sku.goods.sales += count_dict[sku.id]
                        sku.goods.save()
                        order.total_count += count_dict[sku.id]
                        order.total_amount += sku.price * count_dict[sku.id]
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count_dict[sku.id],
                            price=sku.price,
                        )
                        break
                order.total_amount += order.freight
                order.save()
            except serializers.ValidationError:
                raise
            except Exception as e:
                logger.error(e)
                transaction.savepoint_rollback(save_id)
                raise
            else:
                transaction.savepoint_commit(save_id)
        pl = redis_conn.pipeline()
        pl.hdel('cart_%s' % user.id, *cart_selected)
        pl.srem('cart_selected_%s' % user.id, *cart_selected)
        pl.execute()
        return order






